﻿using Furion.JsonSerialization;
using Newtonsoft.Json;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace Magic.Core
{
    public class TouchLetterUnlock
    {
        public static KeyValuePair<CaptchaModel, CaptchaStateModel> Create(byte[] byPicture, int count)
        {
            var code = GenCaptchaCode(count);
            var kv_map = GenCaptchaImage(byPicture, code);

            var img1 = "data:image/png;base64," + Convert.ToBase64String(kv_map.Value);
            var imgId = Guid.NewGuid().ToString();

            return new KeyValuePair<CaptchaModel, CaptchaStateModel>(new CaptchaModel
            {
                Id = imgId,
                Image_Base64 = img1
            }, new CaptchaStateModel
            {
                Id = imgId,
                DataCode = JsonConvert.SerializeObject(kv_map.Key),
                IsSuccess = false
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sItem">用户提交的数据</param>
        /// <param name="vItem">检验数据</param>
        /// <returns></returns>
        public static CaptchaVerifyResult Verify(CaptchaStateModel sItem, CaptchaVerifyModel vItem)
        {
            CaptchaVerifyResult result = new CaptchaVerifyResult() { RepCode = "0000",Success=false };
            var userList = JsonConvert.DeserializeObject<List<LetterPointPosModel>>(sItem.DataCode);
            var dataList = JsonConvert.DeserializeObject<List<LetterPointPosModel>>(vItem.DataCode);

            if (dataList == null || !dataList.Any())
            {
                result.RepCode = "6110";
                result.RepMsg = "验证码已失效，请重新获取";
                return result;
            }

            if (userList == null || !userList.Any())
            {
                result.RepCode = "6111";
                result.RepMsg = "验证码无效";
                return result;
            }

            int allowOffset = 25; // 允许的偏移量(点触容错)
            for (int i = 0; i < userList.Count; i++)
            {
                var xOffset = userList[i].X - dataList[i].X;
                var yOffset = userList[i].Y - dataList[i].Y;
                xOffset = Math.Abs(xOffset); // x轴偏移量                
                yOffset = Math.Abs(yOffset); // y轴偏移量
                                             // 只要有一个点的任意一个轴偏移量大于allowOffset，则验证不通过
                if (xOffset > allowOffset || yOffset > allowOffset)
                {
                    result.RepCode = "6112";
                    result.RepMsg = "验证码错误";
                    return result;
                }
            }

            result.Success = true;
            result.RepMsg = "验证成功";
            return result;
        }


        #region 预定字符
        private static readonly char[] Characters = new[]
        {
            '蛋','总','威','武','神'
        };
        #endregion
        //预定义字体大小(width:em,height:px)
        private static Size[] Sizes = new[] { new Size(18, 24), new Size(21, 28), new Size(24, 32), new Size(27, 36), new Size(30, 40) };
        // 预定义字体颜色
        private static readonly SKColor[] Colors = new[] { SKColors.Black, SKColors.Red, SKColors.DarkBlue, SKColors.Green };
        /// <summary>
        /// 获取指定长度的验证码字符串
        /// </summary>
        /// <param name="length">验证码长度</param>
        /// <returns></returns>
        private static string GenCaptchaCode(int length = 5)
        {
            //用于存放随机产生的字符
            var selected = new char[length];
            //对指定长度的字符逐个赋值
            for (var i = 0; i < length; i++)
            {
                var word = Characters[CaptchaHelper.Random.Next(0, Characters.Length)];  //随机获取字符
                while (selected.Contains(word))
                {
                    word = Characters[CaptchaHelper.Random.Next(0, Characters.Length)];  //随机获取字符
                }
                selected[i] = word;
            }
            //将Char[]转换为字符串
            return new string(selected);
        }
        /// <summary>
        /// 生成验证码图片
        /// </summary>
        /// <param name="code">验证码</param>
        /// <returns></returns>
        private static KeyValuePair<List<LetterLocationModel>, byte[]> GenCaptchaImage(byte[] byPicture, string code)
        {
            //1.定义画布
            var resultMap = new SKBitmap(CaptchaHelper.Bitmap_Width, CaptchaHelper.Bitmap_Height); //创建画布
            var canvas = new SKCanvas(resultMap);//创建画笔
            using (var paint = new SKPaint())
            {
                paint.IsAntialias = true;//消锯齿
                paint.FilterQuality = SKFilterQuality.High;//高质量
                paint.Style = SKPaintStyle.StrokeAndFill;
                paint.StrokeWidth = 1;
                paint.IsDither=true;
                canvas.DrawBitmap(SKBitmap.Decode(byPicture), new SKRect(0, 0, CaptchaHelper.Bitmap_Width, CaptchaHelper.Bitmap_Height), paint);
            }

            //2.计算字符
            var rect_space = 25;
            var rect_width = 50;
            var rect_height = 50;
            var rectList = new Dictionary<string, Rectangle>
            {
                //Row1
                { "c0r0",new Rectangle(rect_space + rect_width * 0, rect_space + rect_height * 0, rect_width, rect_height)},
                { "c1r0",new Rectangle(rect_space + rect_width * 1, rect_space + rect_height * 0, rect_width, rect_height)},
                { "c2r0",new Rectangle(rect_space + rect_width * 2, rect_space + rect_height * 0, rect_width, rect_height)},
                { "c3r0",new Rectangle(rect_space + rect_width * 3, rect_space + rect_height * 0, rect_width, rect_height)},
                { "c4r0",new Rectangle(rect_space + rect_width * 4, rect_space + rect_height * 0, rect_width, rect_height)},
                //Row2
                { "c0r1",new Rectangle(rect_space + rect_width * 0, rect_space + rect_height * 1, rect_width, rect_height)},
                { "c1r1",new Rectangle(rect_space + rect_width * 1, rect_space + rect_height * 1, rect_width, rect_height)},
                { "c2r1",new Rectangle(rect_space + rect_width * 2, rect_space + rect_height * 1, rect_width, rect_height)},
                { "c3r1",new Rectangle(rect_space + rect_width * 3, rect_space + rect_height * 1, rect_width, rect_height)},
                { "c4r1",new Rectangle(rect_space + rect_width * 4, rect_space + rect_height * 1, rect_width, rect_height)},
                //Row3
                { "c0r2",new Rectangle(rect_space + rect_width * 0, rect_space + rect_height * 2, rect_width, rect_height)},
                { "c1r2",new Rectangle(rect_space + rect_width * 1, rect_space + rect_height * 2, rect_width, rect_height)},
                { "c2r2",new Rectangle(rect_space + rect_width * 2, rect_space + rect_height * 2, rect_width, rect_height)},
                { "c3r2",new Rectangle(rect_space + rect_width * 3, rect_space + rect_height * 2, rect_width, rect_height)},
                { "c4r2",new Rectangle(rect_space + rect_width * 4, rect_space + rect_height * 2, rect_width, rect_height)},
            };

            var _kvList = new List<string>();
            var _cList = new List<LetterLocationModel>();
            var codes = code.ToCharArray();
            foreach (var item in codes)
            {
                //尺寸颜色
                var rd_size = CaptchaHelper.Random.Next(0, Sizes.Length - 1);
                var rd_Color = CaptchaHelper.Random.Next(0, Colors.Length);

                //随机取块
                var rd_no = CaptchaHelper.Random.Next(0, rectList.Count - 1);
                var kvItem = rectList.ElementAt(rd_no);
                while (_kvList.Contains(kvItem.Key))
                {
                    rd_no = CaptchaHelper.Random.Next(0, rectList.Count - 1);
                    kvItem = rectList.ElementAt(rd_no);
                }
                _kvList.Add(kvItem.Key);

                //字符位置
                //var rd_x = CaptchaHelper.Random.Next(kvItem.Value.X, kvItem.Value.X + rect_space);
                //var rd_y = CaptchaHelper.Random.Next(kvItem.Value.Y, kvItem.Value.Y + rect_space);
                //var rd_x2 = rd_x + Sizes[rd_size].Height;
                //var rd_y2 = rd_y + Sizes[rd_size].Height;
                var rd_x= kvItem.Value.X;
                var rd_y = kvItem.Value.Y;
                var rd_x2 = kvItem.Value.X + kvItem.Value.Width;
                var rd_y2 = kvItem.Value.Y + kvItem.Value.Height;

                //生成对象
                _cList.Add(new LetterLocationModel
                {
                    Letter = item.ToString(),
                    fontColor = Colors[rd_Color],
                    fontSize = Sizes[rd_size].Width,
                    x = rd_x,
                    y = rd_y,
                    x2 = rd_x2,
                    y2 = rd_y2
                });
            }


            //3.写字画图
            foreach (var item in _cList)
            {
                using (var paint = new SKPaint())
                {
                    paint.Typeface = SKTypeface.FromFamilyName("宋体");
                    paint.TextEncoding = SKTextEncoding.Utf8;
                    paint.IsAntialias = true;//消锯齿
                    paint.FilterQuality = SKFilterQuality.High;//高质量
                    paint.Style = SKPaintStyle.StrokeAndFill;
                    paint.StrokeWidth = 1;
                    paint.Color = item.fontColor;
                    paint.FakeBoldText = false;
                    paint.TextSize = item.fontSize;

                    SKRect textBounds = new SKRect();
                    paint.MeasureText(item.Letter, ref textBounds);
                    canvas.DrawText(item.Letter, new SKPoint((int)new int[]{ item.x, item.x2 }.Average(), (int)new int[] { item.y, item.y2 }.Average()), paint);
                }
            }


            //4.输出结果
            var resultKey = new List<string>();
           // _cList.ForEach(o => { resultKey.Add(o.ToString()); });

            var image = SKImage.FromBitmap(resultMap);
            var resultValue = image.Encode(SKEncodedImageFormat.Png, 100).ToArray();

            return new KeyValuePair<List<LetterLocationModel>, byte[]>(_cList, resultValue);
        }
    }

    public class LetterLocationModel
    {
        public string Letter { get; set; }
        public float fontSize { get; set; }
        public SKColor fontColor { get; set; }
        public int x { get; set; }
        public int x2 { get; set; }
        public int y { get; set; }
        public int y2 { get; set; }
        public override string ToString()
        {
            return "{\"Letter\":\"" + Letter + " \",\"x\":" + x + ",\"y\":" + y + ",\"x2\":" + x2 + ",\"y2\":" + y2 + "}";
        }
    }

    /// <summary>
    /// 记录正确位置
    /// </summary>
    public class LetterPointPosModel
    {
        public int X { get; set; }

        public int Y { get; set; }
    }
}
